package com.event.cacheclear.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.event.cacheclear.service.IBatchClearCacheService;
import com.event.cacheclear.service.IClearCacheService;
import com.event.common.face.IClearNameSpace;
import com.event.common.model.AliasClearNameSpace;
import com.event.common.model.EventCacheKey;
import com.event.common.util.KeyParserUtil;
import com.event.core.parse.CacheableParse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import static java.util.stream.Collectors.groupingBy;

/**
 * @Description 批量清理缓存服务
 * @Author Bing
 * @Date 2024/10/29 11:10
 */
@Slf4j
@Service
@ConditionalOnBean(CacheableParse.class)
public class BatchClearCacheService implements IBatchClearCacheService {

    @Autowired
    @Lazy
    private AliasClearNameSpace aliasClearNameSpaces;

    @Autowired(required = false)
    @Lazy
    private IClearCacheService clearCacheService;

    @Override
    public void batchClearInsertCache(String namespaceAlias, Supplier<List<Serializable>> idList) {
        IClearNameSpace<Object> clearNameSpace = checkClearNameSpace(namespaceAlias);
        if(ObjectUtil.isNull(clearNameSpace)){
            return;
        }
        List<Serializable> ids = idList.get();
        batchClearCacheBefore(clearNameSpace, ids);
    }

    @Override
    public void batchClearUpdateCache(String namespaceAlias, List<Serializable> ids, Runnable runnable) {
        IClearNameSpace<Object> clearNameSpace = checkClearNameSpace(namespaceAlias);
        if(ObjectUtil.isNull(clearNameSpace)){
            return;
        }
        List<Serializable> busIds = batchClearCacheBefore(clearNameSpace, ids);
        runnable.run();
        batchClearCacheAfter(clearNameSpace, busIds);
    }

    @Override
    public void clearCache(String namespaceAlias, List<Serializable> busIds) {
        if(ObjectUtil.isNull(clearCacheService)){
            return;
        }
        List<EventCacheKey> cacheKeys = clearCacheService.getAliasCacheKey(namespaceAlias);
        if(CollUtil.isEmpty(cacheKeys)){
            return;
        }
        clearCache(cacheKeys,busIds);
    }

    /**
     * 获取业务id
     * @param clearNameSpace
     * @param ids
     * @return
     */
    @Override
    public List<Serializable> getBusIdsByBatch(IClearNameSpace<Object> clearNameSpace, List<Serializable> ids){
        List<Object> objects = clearNameSpace.getRecordByIds(ids);
        if(CollUtil.isEmpty(objects)){
            return new ArrayList<>();
        }
        Function<Object,Object>[] idValues = clearNameSpace.idValues();
        if(ObjectUtil.isNull(idValues)){
            return new ArrayList<>();
        }
        Set<Serializable> result = new HashSet<>(idValues.length*objects.size());
        for(Object object : objects){
            for(Function<Object,Object> idValue : idValues){
                Object value = idValue.apply(object);
                if(ObjectUtil.isNull(value)){
                    continue;
                }
                result.add(value.toString());
            }
        }
        return new ArrayList<>(result);
    }

    @Override
    public IClearNameSpace<Object> checkClearNameSpace(String alias) {
        if(ObjectUtil.isNull(clearCacheService)){
            return null;
        }
        // 获取命名空间缓存key
        List<EventCacheKey> cacheKeys = clearCacheService.getAliasCacheKey(alias);
        if(CollUtil.isEmpty(cacheKeys)){
            return null;
        }
        // 获取清除命名空间服务
        Map<String, IClearNameSpace<Object>> aliasClearNameSpacesMap =  aliasClearNameSpaces.getAliasClearNameSpacesMap();
        if(CollUtil.isEmpty(aliasClearNameSpacesMap)){
            return null;
        }
        IClearNameSpace<Object> clearNameSpace = aliasClearNameSpacesMap.get(alias);
        if(Objects.isNull(clearNameSpace)){
            return null;
        }
        return clearNameSpace;
    }

    @Override
    public List<Serializable> clearCacheByIds(IClearNameSpace<Object> clearNameSpace, String alias, List<Serializable> idValues) {
        if(CollUtil.isEmpty(idValues)){
            clearCache(alias, new ArrayList<>());
            return new ArrayList<>();
        }
        List<Serializable> busIds = getBusIdsByBatch(clearNameSpace,idValues);
        clearCache(alias, busIds);
        return busIds;
    }

    /**
     * 批量删除缓存前
     * @param clearNameSpace
     * @param ids
     * @return
     */
    private List<Serializable> batchClearCacheBefore(IClearNameSpace<Object> clearNameSpace, List<Serializable> ids){
        List<Serializable> busIds = clearCacheByIds(clearNameSpace,clearNameSpace.namespaceAlias(),ids);
        return busIds;
    }

    /**
     * 批量删除缓存前
     * @param clearNameSpace
     * @return
     */
    private void batchClearCacheAfter(IClearNameSpace<Object> clearNameSpace, List<Serializable> busIds){
        if(TransactionSynchronizationManager.isActualTransactionActive()){
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    clearCache(clearNameSpace.namespaceAlias(),busIds);
                }
            });
            return;
        }
        clearCache(clearNameSpace.namespaceAlias(),busIds);
    }

    /**
     * 批量删除缓存
     * @param cacheKeys
     */
    private void clearCache(List<EventCacheKey> cacheKeys, List<Serializable> busIds){
        Map<String, IClearNameSpace<Object>> aliasClearNameSpacesMap = aliasClearNameSpaces.getAliasClearNameSpacesMap();
        // 区分有业务ID，还是全部
        String typeId = "ID";
        String typeAll = "ALL";
        Map<String,List<EventCacheKey>> groupCacheKey = cacheKeys.stream().collect(groupingBy(item-> {
            return StrUtil.isNotBlank(item.getBusIdName()) ? typeId : typeAll;
        }));
        // 删除业务ID的缓存
        List<EventCacheKey> idCacheList = groupCacheKey.get(typeId);
        if(CollUtil.isNotEmpty(idCacheList)){
            for(EventCacheKey cache : idCacheList){
                IClearNameSpace<Object> clearNameSpace = aliasClearNameSpacesMap.get(cache.getNamespaceAlias());
                if(ObjectUtil.isNotNull(clearNameSpace)){
                    clearByBusIds(cache,busIds);
                }
            }
        }
        // 删除全部范围的缓存
        List<EventCacheKey> allCacheList = groupCacheKey.get(typeAll);
        if(CollUtil.isEmpty(allCacheList)){
            return;
        }
        for(EventCacheKey allCache : allCacheList){
            clearAll(allCache);
        }
    }

    /**
     * 清除所有缓存
     * @param cacheKey
     */
    private void clearAll(EventCacheKey cacheKey){
        clearCacheService.clearCache(KeyParserUtil.getCacheKey(cacheKey));
    }

    /**
     * 根据id清除缓存
     * @param cacheKey
     */
    private void clearByBusIds(EventCacheKey cacheKey,List<Serializable> busIds){
        if(CollUtil.isEmpty(busIds)){
            return;
        }
        busIds.stream().forEach(busId -> {
            // 设置id值到key里
            cacheKey.setBusIdValue(busId.toString());
            clearCacheService.clearCache(KeyParserUtil.getCacheKey(cacheKey));
        });
    }
}